/**
 * 
 */
package com.easidea.tim.service.inventory;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springside.core.service.EntityService;

import com.easidea.tim.dao.base.FlowNoDao;
import com.easidea.tim.dao.commodity.ProductDao;
import com.easidea.tim.dao.inventory.CheckInOutDao;
import com.easidea.tim.dao.inventory.CheckInOutItemDao;
import com.easidea.tim.dao.inventory.InventoryDao;
import com.easidea.tim.dao.inventory.InventoryItemDao;
import com.easidea.tim.dao.inventory.InventoryMarginItemDao;
import com.easidea.tim.dao.inventory.StorageDao;
import com.easidea.tim.entity.commodity.Product;
import com.easidea.tim.entity.inventory.CheckInOut;
import com.easidea.tim.entity.inventory.CheckInOutItem;
import com.easidea.tim.entity.inventory.Inventory;
import com.easidea.tim.entity.inventory.InventoryItem;
import com.easidea.tim.entity.inventory.InventoryMarginItem;
import com.easidea.tim.entity.inventory.Storage;
import com.easidea.tim.util.Page;
import com.easidea.tim.util.TimConstant.FlowNoType;

/**
 * @author Harrison
 * 
 */
public class InventoryServcie extends EntityService<Inventory, InventoryDao> {

	private static final Logger log = Logger.getLogger(InventoryServcie.class);

	private InventoryDao inventoryDao;
	private InventoryItemDao inventoryItemDao;
	private InventoryMarginItemDao inventoryMarginItemDao;
	private ProductDao productDao;
	private StorageDao storageDao;
	private CheckInOutDao checkInOutDao;
	private CheckInOutItemDao checkInOutItemDao;
	private FlowNoDao flowNoDao;

	/**
	 * 添加盘点记录，同时锁定对应的库存数据
	 * 
	 * @param ti
	 * @return
	 */
	public boolean saveInventory(Inventory ti) {
		boolean rst = false;
		Inventory inv = null;
		if (ti != null && ti.getId() == -1) {
			inv = marshallInventoryEntity(ti);
		} else {
			inv = ti;
		}

		if (inv != null && inv.getInventoryItemList() != null) {
			Inventory newTi = null;
			if (inv.getId() != null)
				newTi = inventoryDao.get(inv.getId());

			if (newTi != null && newTi.getInventoryItemList().size() > 0) {
				// 修改
				Double totalMeterNum = newTi.getTotalMeterNum();
				Double totalPiNum = newTi.getTotalPiNum();
				for (InventoryItem tid : inv.getInventoryItemList()) {
					if (tid != null) {
						tid.setId(null);
						tid.setInventory(newTi);
						inventoryItemDao.save(tid);
						totalMeterNum = totalMeterNum + tid.getMeterNum();
						totalPiNum++;
					}
				}

				newTi.setTotalMeterNum(totalMeterNum);
				newTi.setTotalPiNum(totalPiNum);
				inventoryDao.merge(newTi);
			} else {
				// 保存
				inv.setFlowNo(flowNoDao
						.genNextFlowNo(FlowNoType.TAKE_INVENTORY));
				inventoryDao.save(inv);
				for (InventoryItem tid : inv.getInventoryItemList()) {
					if (tid != null) {
						tid.setId(null);
						tid.setInventory(inv);
						inventoryItemDao.save(tid);
					}
				}

			}
			rst = true;
		}
		return rst;
	}

	/**
	 * 清理垃圾数据
	 * 
	 * @param inventory
	 * @return
	 */
	private Inventory marshallInventoryEntity(Inventory inventory) {
		Inventory rstInv = null;
		if (inventory != null && inventory.getProduct() != null
				&& inventory.getProduct().getId() != null
				&& inventory.getProduct().getId() != -1) {

			rstInv = new Inventory();
			Product product = productDao.get(inventory.getProduct().getId());
			if (product != null) {
				rstInv.setProduct(product);
				rstInv.setProductName(product.getName());
				rstInv.setColorCode(product.getColorCode());
				rstInv.setInventoryItemList(inventory.getInventoryItemList());
				rstInv.setStatus(Inventory.INVENTORY_STATUS_BOOK);
				rstInv.setInventoryMarginList(null);
				rstInv.setTotalMarginNum(null);
				rstInv.setTotalMarginPiNum(null);
				rstInv.setCreator(inventory.getCreator());
				rstInv.setModifier(rstInv.getCreator());
				rstInv.setInventoryDate(inventory.getInventoryDate());
				rstInv.setSampleFlag(inventory.getSampleFlag());
				rstInv.setTotalMeterNum(inventory.getTotalMeterNum());
				rstInv.setTotalPiNum(inventory.getTotalPiNum());
			}
		}
		return rstInv;
	}

	public boolean updateItemMeterNum(String name, String colorCode,
			Boolean sampleFlag, Integer index, Double value, Date inventoryDate) {
		Criteria cte = inventoryDao.createUnDeletedCriteria();
		cte.add(Restrictions.eq("productName", name));
		cte.add(Restrictions.eq("colorCode", colorCode));
		cte.add(Restrictions.eq("sampleFlag", sampleFlag));
		cte.add(Restrictions.eq("inventoryDate", inventoryDate));
		Inventory ti = (Inventory) cte.uniqueResult();
		if (ti != null && ti.getInventoryItemList() != null
				&& ti.getInventoryItemList().size() > 0) {
			InventoryItem tid = ti.getInventoryItemList().get(index);
			ti.setTotalMeterNum(ti.getTotalMeterNum() - tid.getMeterNum()
					+ value);
			tid.setMeterNum(value);
			return true;
		}
		return false;
	}

	/**
	 * 
	 * @param name
	 * @param colorCode
	 * @param sampleFlag
	 * @param operator
	 * @param startDate
	 * @param endDate
	 * @param status
	 * @param page
	 * @return
	 */
	public Page getInventoryList(String name, String colorCode,
			Boolean sampleFlag, String operator, Date startDate, Date endDate,
			String status, Page page) {

		Criteria rowCountsCte = genCriteria(name, colorCode, sampleFlag,
				operator, startDate, endDate, (status == null || status.trim()
						.length() == 0) ? null : new Short(status));
		rowCountsCte.setProjection(Projections.count("id"));
		Integer totalCounts = (Integer) rowCountsCte.uniqueResult();

		Criteria cte = genCriteria(name, colorCode, sampleFlag, operator,
				startDate, endDate,
				(status == null || status.trim().length() == 0) ? null
						: new Short(status));
		int index = Page.getStartOfPage(page.getCurrentPageNo(), page
				.getPageSize());
		cte.addOrder(Order.desc("inventoryDate"));
		cte.setFirstResult(index);
		cte.setMaxResults(page.getPageSize());
		List<Inventory> rtl = (List<Inventory>) cte.list();

		Page resultPage = new Page(index, totalCounts, page.getPageSize(), rtl);
		resultPage.setCurrentPageNo(page.getCurrentPageNo());
		return resultPage;
	}

	private Criteria genCriteria(String name, String colorCode,
			Boolean sampleFlag, String operator, Date startDate, Date endDate,
			Short status) {
		Criteria cte = inventoryDao.createUnDeletedCriteria();
		if (name != null && name.length() > 0)
			cte.add(Restrictions.ilike("productName", "%" + name + "%"));
		if (colorCode != null && colorCode.length() > 0)
			cte.add(Restrictions.ilike("colorCode", "%" + colorCode + "%"));
		if (sampleFlag != null)
			cte.add(Restrictions.eq("sampleFlag", sampleFlag));
		if (operator != null && operator.length() > 0)
			cte.add(Restrictions.eq("creator", operator));
		if (startDate != null && endDate != null) {
			switch (startDate.compareTo(endDate)) {
			case 0:
				cte.add(Restrictions.eq("inventoryDate", startDate));
				break;

			case -1:
				cte.add(Restrictions.between("inventoryDate", startDate,
						endDate));
				break;

			default:
				break;
			}
		}
		if (status != null && status.shortValue() != 0)
			cte.add(Restrictions.eq("status", status));
		return cte;
	}

	public Inventory getInventoryDetail(Long id, String type) {
		Inventory ti = null;
		if (id != null && type != null) {
			ti = inventoryDao.get(id);
			// if(type.equalsIgnoreCase("margin")){
			// //提取差异数据
			// Criteria cte = inventoryMarginItemDao.createUnDeletedCriteria();
			// cte.add(Restrictions.eq("inventory.id", id));
			// List<InventoryMarginItem> marginList =
			// (ArrayList<InventoryMarginItem>)cte.list();
			// ti.setInventoryMarginList(marginList);
			// }
			// if(type.equalsIgnoreCase("detail")){
			// //提取普通明细数据
			// ti.getInventoryItemList();
			// }
		}
		return ti;
	}

	public Boolean removeDust(Long id) {
		if (id != null) {
			return inventoryDao.deleteInventory(id);
		} else
			return false;
	}

	/**
	 * 改变状态
	 * 
	 * @param id
	 * @param type
	 * @return
	 */
	public Boolean changeStatus(Long id, String type) {
		if (id != null && type != null) {
			Inventory inv = inventoryDao.get(id);
			if (inv != null) {
				if (type.equalsIgnoreCase("inventorycompletesuccess")) {
					// 盘点结束，应该进行损溢调整
					tuneInvnetoryStorage(inv);
					inv.setStatus(Inventory.INVENTORY_STATUS_COMPLETE);
					return true;
				}

				if (type.equalsIgnoreCase("tunefinishedsuccess")) {
					// 盘点调整完成，不做任何处理，只是改状态
					inv.setStatus(Inventory.INVENTORY_STATUS_SAVE);
					return true;
				}
			}

		}
		return false;
	}

	/**
	 * 盘点损溢出入库处理
	 * 
	 * @param marginList
	 * @param invId
	 *            盘点编号
	 */
	private void tuneInvnetoryStorage(Inventory inv) {
		if (inv.getInventoryMarginList() != null
				&& inv.getInventoryMarginList().size() > 0) {
			DateFormat df = new SimpleDateFormat("yyyy年MM月dd日");

			CheckInOut inventoryCheckIn = new CheckInOut();// 盘盈入库记录
			inventoryCheckIn.setCreator(inv.getCreator());
			inventoryCheckIn.setModifier(inv.getModifier());
			inventoryCheckIn
					.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKIN);
			inventoryCheckIn
					.setType(CheckInOut.CHECKINOUT_TYPE_CHECKIN_INVENTORY_PROFIT);
			inventoryCheckIn.setDescription("盘点日期： " + df.format(new Date())
					+ " ，盘点编号： " + inv.getFlowNo() + " 出入库方向：盘盈入库 ");

			CheckInOut storageCheckOut = new CheckInOut();// 盘亏出库记录
			storageCheckOut.setCreator(inv.getCreator());
			storageCheckOut.setModifier(inv.getModifier());
			storageCheckOut
					.setDirection(CheckInOut.CHECKINOUT_DIRECTION_CHECKOUT);
			storageCheckOut
					.setType(CheckInOut.CHECKINOUT_TYPE_CHECKOUT_INVENTORY_LOSS);
			storageCheckOut.setDescription("盘点日期： " + df.format(new Date())
					+ " ，盘点编号： " + inv.getFlowNo() + " 出入库方向：盘亏出库 ");

			List<CheckInOutItem> checkInList = new ArrayList<CheckInOutItem>(); // 入库 -- 盘盈
			List<CheckInOutItem> checkOutList = new ArrayList<CheckInOutItem>(); // 出库 -- 盘亏

			Double totalCheckOutPiSummary = 0d;
			Double totalCheckOutMeterSummary = 0d;

			Double totalCheckInPiSummary = 0d;
			Double totalCheckInMeterSummary = 0d;

			if (inv.getSampleFlag() && inv.getInventoryMarginList() != null) {
				// 剪样
				InventoryMarginItem item = inv.getInventoryMarginList().get(0);
				
				if (item != null) {
					
					Storage existSampleSt = null;
					if(item.getStorage() != null ){
						List<Storage> existSampleStList = storageDao.getSampleStorage(item.getStorage().getProduct().getId());
						if(existSampleStList != null && existSampleStList.size() > 0){
							existSampleSt = existSampleStList.get(0);
						}
					}
					

					switch (item.getMarginType().shortValue()) {
					case 2:
						// 盘盈
						Storage oldSt = item.getStorage();
						if (oldSt != null && oldSt.getId() != null) {
							
							
							if (existSampleSt != null) {
								// 对应库存数据存在
								existSampleSt.setMeterNum(item.getInventoryItem().getMeterNum()); // 用输入的数据替换库存
								
								CheckInOutItem inItem = new CheckInOutItem();
								inItem.setCreateTime(new Date());
								inItem.setCreator(inv.getCreator());
								inItem.setModifier(inv.getModifier());
								inItem.setModifyTime(new Date());
								inItem.setInputMeterNum(item.getMarginNum());
								
								inItem.setStorage(existSampleSt);

								checkInList.add(inItem);

							} else {
								// 插入缺失的库存数据
								Storage newSt = appendInventoryStorage(inv,
										item);

								CheckInOutItem inItem = new CheckInOutItem();
								inItem.setCreateTime(new Date());
								inItem.setCreator(inv.getCreator());
								inItem.setModifier(inv.getModifier());
								inItem.setModifyTime(new Date());
								inItem.setInputMeterNum(item.getMarginNum());
								inItem.setStorage(newSt);

								checkInList.add(inItem);
							}
						} else {
							// 插入缺失的库存数据
							Storage newSt = appendInventoryStorage(inv, item);

							CheckInOutItem inItem = new CheckInOutItem();
							inItem.setCreateTime(new Date());
							inItem.setCreator(inv.getCreator());
							inItem.setModifier(inv.getModifier());
							inItem.setModifyTime(new Date());
							inItem.setInputMeterNum(item.getMarginNum());
							inItem.setStorage(newSt);

							checkInList.add(inItem);
						}

						totalCheckInMeterSummary = existSampleSt != null ? item.getMarginNum() - existSampleSt.getMeterNum() : item.getMarginNum();
						totalCheckInPiSummary = 1d;

						break;

					case 1:
						// 盘亏

						existSampleSt.setMeterNum(item.getInventoryItem().getMeterNum());
						
						CheckInOutItem outItem = new CheckInOutItem();
						outItem.setCreateTime(new Date());
						outItem.setCreator(inv.getCreator());
						outItem.setModifier(inv.getModifier());
						outItem.setModifyTime(new Date());
						outItem.setStorage(existSampleSt);
						outItem.setInputMeterNum(item.getMarginNum());
						checkOutList.add(outItem);

						totalCheckOutMeterSummary = item.getMarginNum();
						totalCheckOutPiSummary = 1d;
						break;
					}
				}
			} else {
				// 非剪样
				for (InventoryMarginItem item : inv.getInventoryMarginList()) {
					if (item != null) {
						if (item.getMarginType().shortValue() == InventoryMarginItem.MARGIN_TYPE_INVENTORY_ITEM
								.shortValue()
								&& item.getInventoryItem() != null) {
							// 盘盈，Inventory是实物多于账面的Storage
							CheckInOutItem inItem = new CheckInOutItem();
							inItem.setCheckInOut(inventoryCheckIn);
							inItem.setCreateTime(new Date());
							inItem.setCreator(inv.getCreator());
							inItem.setModifier(inv.getModifier());
							inItem.setModifyTime(new Date());
							inItem.setInputMeterNum(item.getMarginNum());

							Storage st = new Storage();
							st.setMeterNum(item.getMarginNum());
							st.setName(inv.getProductName());
							st.setProduct(inv.getProduct());
							st.setSampleFlag(inv.getSampleFlag());
							st.setCreator(item.getCreator());
							st.setModifier(item.getModifier());
							storageDao.save(st); // 保存库存数据

							inItem.setStorage(st);
							checkInList.add(inItem);
							totalCheckInPiSummary++;
							totalCheckInMeterSummary = totalCheckInMeterSummary
									+ item.getMarginNum();
						}
						if (item.getMarginType().shortValue() == InventoryMarginItem.MARGIN_TYPE_STORAGE
								.shortValue()
								&& item.getStorage() != null) {
							// 盘亏
							CheckInOutItem outItem = new CheckInOutItem();
							outItem.setCheckInOut(storageCheckOut);
							outItem.setCreateTime(new Date());
							outItem.setCreator(inv.getCreator());
							outItem.setModifier(inv.getModifier());
							outItem.setModifyTime(new Date());
							outItem.setInputMeterNum(item.getMarginNum());
							checkOutList.add(outItem);
							if (item.getStorage().getId() != null) {
								storageDao.removeById(item.getStorage().getId());
							}
							outItem.setStorage(item.getStorage());

							totalCheckOutPiSummary++;
							totalCheckOutMeterSummary = totalCheckOutMeterSummary
									+ item.getMarginNum();
						}
					}
				}

			}

			inventoryCheckIn.setMeterNumSummary(totalCheckInMeterSummary);
			inventoryCheckIn.setPiNumSummary(totalCheckInPiSummary);
			inventoryCheckIn.setItems(checkInList);

			storageCheckOut.setMeterNumSummary(totalCheckOutMeterSummary);
			storageCheckOut.setPiNumSummary(totalCheckOutPiSummary);
			storageCheckOut.setItems(checkOutList);

			if (inventoryCheckIn.getMeterNumSummary().doubleValue() != 0)
				saveCheckInOut(inventoryCheckIn);
			if (storageCheckOut.getMeterNumSummary().doubleValue() != 0)
				saveCheckInOut(storageCheckOut);
		}
	}

	/**
	 * 插入盘点缺失库存
	 * 
	 * @param inv
	 * @param item
	 * @return
	 */
	private Storage appendInventoryStorage(Inventory inv,
			InventoryMarginItem item) {
		Storage oldSt = new Storage();
		oldSt.setCreateTime(new Date());
		oldSt.setCreator(item.getCreator());
		oldSt.setModifier(item.getModifier());
		oldSt.setModifyTime(new Date());
		oldSt.setName(inv.getProductName());
		oldSt.setSampleFlag(true);
		oldSt.setMeterNum(item.getInventoryItem().getMeterNum());
		oldSt.setProduct(inv.getProduct());
		storageDao.save(oldSt);
		return oldSt;
	}

	private void saveCheckInOut(CheckInOut cio) {
		if (cio != null && cio.getItems() != null) {
			checkInOutDao.save(cio);
			for (CheckInOutItem item : cio.getItems()) {
				item.setCheckInOut(cio);
				checkInOutItemDao.save(item);
			}
		}

	}

	/**
	 * 登记完毕，产生差异数据，并修改盘点记录
	 * 
	 * @param id
	 * @return
	 */
	public Boolean inputFinished(Long id) {
		boolean rst = false;
		log.debug("in InventoryService inputFinished method ....");
		if (id == null)
			return rst;
		Inventory inv = inventoryDao.get(id);
		if (inv != null) {

			if (!inv.getSampleFlag()) {
				// 非剪样情况下

				List<Storage> marginStorageList = getStorageNotExistListInInventoryItem(
						inv.getProduct().getId(), id, inv.getSampleFlag());
				// 库存数据在盘点记录中不存在的数据
				List<InventoryItem> marginInventoryItemList = getInventoryItemNotExistInStorage(
						inv.getProduct().getId(), id, inv.getSampleFlag());
				// 盘点数据在库存数据中不存在的数据

				List<Double> existsNumList = getAllExistsMeterNums(inv
						.getProduct().getId(), id, inv.getSampleFlag());// 获得两个表中都有的数据

				for (Double meterNum : existsNumList) {
					Map<String, List> marginListMap = getMarginInExistList(inv
							.getProduct().getId(), inv.getSampleFlag(), id,
							meterNum);
					if (marginListMap != null) {
						if (marginListMap.containsKey("storage"))
							marginStorageList
									.addAll((List<Storage>) marginListMap
											.get("storage"));
						if (marginListMap.containsKey("inventory_item"))
							marginInventoryItemList
									.addAll((List<InventoryItem>) marginListMap
											.get("inventory_item"));
					}
				} //产生重复但不存在的数据

//				double totalMarginPiNum = marginStorageList.size()
//						+ marginInventoryItemList.size();
//				double totalMarginMeterNum = 0d;
//				for (Storage st : marginStorageList) {
//					if (st != null && st.getMeterNum() != null)
//						totalMarginMeterNum = totalMarginMeterNum
//								+ st.getMeterNum();
//				}
//				for (InventoryItem ii : marginInventoryItemList) {
//					if (ii != null && ii.getMeterNum() != null)
//						totalMarginMeterNum = totalMarginMeterNum
//								+ ii.getMeterNum();
//				}
				
				
				saveInventoryMarginItem(marginInventoryItemList,
						marginStorageList, inv); // 保存差异数据

				Map<String, Double> marginMap = calculateMarginPiNumAndMeterNum(inv);
				if(marginMap != null){
					inv.setTotalMarginNum(marginMap.get("meterNum"));
					inv.setTotalMarginPiNum(marginMap.get("piNum"));
				}
				inv.setStatus(Inventory.INVENTORY_STATUS_CONFIRM);
				log
						.info("inventory input finish process completed , totalMarginPiNum: "
								+ inv.getTotalMarginPiNum()
								+ " , totalMarginMeterNum: "
								+ inv.getTotalMarginNum());
				inventoryDao.merge(inv);
				rst = true;

			} else {
				// 剪样情况下
				if (inv.getInventoryItemList().size() > 1) {
					log
							.debug("This inventory data is illegal, sample flag is true but the inventory item list size bigger than 1, system will take the first only");
				}
				InventoryItem ii = inv.getInventoryItemList().get(0);
				if (ii != null) {
					Storage st = null;
					List<Storage> stList = storageDao.getSampleStorage(inv.getProduct().getId());
					if(stList != null && stList.size()>0){
						st = stList.get(0);
					}
					if (st != null && st.getId() != null) {
						// 库存数据存在
						if (st.getMeterNum().doubleValue() > ii.getMeterNum()
								.doubleValue()) {
							// 库存数据大于实际盘点数据，盘亏
							InventoryMarginItem mItem = new InventoryMarginItem();
							mItem.setCreator(ii.getCreator());
							mItem.setModifier(ii.getModifier());
							mItem.setInventory(inv);
							mItem.setInventoryItem(ii);
							mItem.setMarginNum(ii.getMeterNum().doubleValue()
									- st.getMeterNum().doubleValue());
							mItem.setStorage(st);
							mItem
									.setMarginType(InventoryMarginItem.MARGIN_TYPE_STORAGE);
							inventoryMarginItemDao.save(mItem);

							inv.setTotalMarginNum(mItem.getMarginNum());
							inv.setTotalMarginPiNum(0d);
							inv.setStatus(Inventory.INVENTORY_STATUS_CONFIRM);
							inventoryDao.merge(inv);
							rst = true;
						}

						if (st.getMeterNum().doubleValue() < ii.getMeterNum()
								.doubleValue()) {
							// 库存数据小于实际盘点数据，盘盈
							InventoryMarginItem mItem = new InventoryMarginItem();
							mItem.setCreator(inv.getCreator());
							mItem.setModifier(inv.getModifier());
							mItem.setInventory(inv);
							mItem.setInventoryItem(ii);
							mItem.setMarginNum(ii.getMeterNum().doubleValue()
									- st.getMeterNum().doubleValue());
							mItem.setStorage(st);
							mItem
									.setMarginType(InventoryMarginItem.MARGIN_TYPE_INVENTORY_ITEM);
							inventoryMarginItemDao.save(mItem);

							inv.setTotalMarginNum(mItem.getMarginNum());
							inv.setTotalMarginPiNum(0d);
							inv.setStatus(Inventory.INVENTORY_STATUS_CONFIRM);
							inventoryDao.merge(inv);
							rst = true;
						}
					} else {
						// 库存数据不存在，盘盈
						InventoryMarginItem mItem = new InventoryMarginItem();
						mItem.setCreator(inv.getCreator());
						mItem.setModifier(inv.getModifier());
						mItem.setInventory(inv);
						mItem.setInventoryItem(ii);
						mItem.setMarginNum(ii.getMeterNum().doubleValue());
						mItem
								.setMarginType(InventoryMarginItem.MARGIN_TYPE_INVENTORY_ITEM);
						inventoryMarginItemDao.save(mItem);

						inv.setTotalMarginNum(mItem.getMarginNum());
						inv.setTotalMarginPiNum(1d);
						inv.setStatus(Inventory.INVENTORY_STATUS_CONFIRM);
						inventoryDao.merge(inv);
						rst = true;
					}
				}
			}

		} else {
			log
					.error(" inventory input finish process failure: the inventory id does not exist "
							+ id);
		}
		return rst;
	}

	
	private Map<String, Double> calculateMarginPiNumAndMeterNum(Inventory inv){
		if(inv != null){
			String invHql = "SELECT count(it.id), sum(it.meterNum) FROM " + InventoryItem.class.getName() + " it WHERE it.inventory.id = " + inv.getId();
			Query invQuery = inventoryItemDao.createQuery(invHql);
			List<Object[]> invResult = (List<Object[]>)invQuery.list();
			
			String storageHql = "SELECT count(st.id), sum(st.meterNum) FROM " + Storage.class.getName() + " st WHERE st.deleted = 0 AND st.product.id = " + inv.getProduct().getId() + " AND st.sampleFlag = " + inv.getSampleFlag();
			Query stQuery = storageDao.createQuery(storageHql);
			List<Object[]> stResult = (List<Object[]>)stQuery.list();
			
			Long invPiNum = (Long)invResult.get(0)[0];
			//Double invMeterNum = ((BigDecimal)invResult.get(0)[1]).doubleValue();
			Double invMeterNum = ((Double)invResult.get(0)[1]);
			Long stPiNum = (Long)stResult.get(0)[0];
			//Double stMeterNum = ((BigDecimal)stResult.get(0)[1]).doubleValue();
			Double stMeterNum = ((Double)stResult.get(0)[1]);
			Map rtnMap = new HashMap<String, Double>();
			rtnMap.put("piNum", invMeterNum == 0 ? stPiNum * -1 : new Double(invPiNum - stPiNum));
			rtnMap.put("meterNum", invMeterNum == null || stMeterNum == null ? (stMeterNum == null ? invMeterNum : stMeterNum * -1) : invMeterNum - stMeterNum);
			return rtnMap;
		}
		return null;
	}
	
	/**
	 * 补充差异数据列表
	 * 
	 * @param marginInventoryItemList
	 * @param marginStorageList
	 * @param inventoryId
	 */
	private void saveInventoryMarginItem(
			List<InventoryItem> marginInventoryItemList,
			List<Storage> marginStorageList, Inventory inv) {
		if (marginInventoryItemList != null
				&& marginInventoryItemList.size() > 0 && inv.getTotalMeterNum().doubleValue() != 0d) {
			for (InventoryItem item : marginInventoryItemList) {
				if (item != null && item.getMeterNum() != null) {
					InventoryMarginItem mi = new InventoryMarginItem();
					mi.setCreateTime(new Date());
					mi.setCreator(inv.getCreator());
					mi.setInventory(item.getInventory());
					mi.setModifier(inv.getModifier());
					mi.setModifyTime(new Date());
					mi.setInventoryItem(item);
					mi.setMarginNum(item.getMeterNum());
					mi
							.setMarginType(InventoryMarginItem.MARGIN_TYPE_INVENTORY_ITEM);
					inventoryMarginItemDao.save(mi);
				}
			}
		}

		if (marginStorageList != null && marginStorageList.size() > 0) {
			for (Storage st : marginStorageList) {
				if (st != null && st.getMeterNum() != null) {
					InventoryMarginItem mi = new InventoryMarginItem();
					mi.setCreateTime(new Date());
					mi.setCreator(inv.getCreator());
					mi.setModifier(inv.getModifier());
					mi.setModifyTime(new Date());
					mi.setInventory(inv);
					mi.setStorage(st);
					mi.setMarginNum(st.getMeterNum());
					mi.setMarginType(InventoryMarginItem.MARGIN_TYPE_STORAGE);
					inventoryMarginItemDao.save(mi);
				}
			}

		}
	}

	/**
	 * 查询库存数据中在盘点记录中不存在的数据
	 * 
	 * @author Harrison
	 * @param productId
	 *            布品ID
	 * @param inventoryId
	 *            盘点ID
	 * @return
	 */
	private List<Storage> getStorageNotExistListInInventoryItem(Long productId,
			Long inventoryId, Boolean sampleFlag) {
		final String hql = "select id, deleted, modifier, modified_time, creator, create_time, name, sample_flag, meter_num, charge_flag, charged_flow_no, product_id"
				+ " from tim_inventory_storage where id not in"
				+ "("
				+ " select s.id from tim_inventory_storage s , "
				+ " (select it.id as item_id , it.meter_num as item_number , ii.product_id as inventory_product_id "
				+ "  from tim_inventory_inventory ii , tim_inventory_inventory_item it "
				+ "  where it.inventory_id = ii.id and it.inventory_id ="
				+ inventoryId
				+ " and it.deleted = 0"
				+ " ) tmp"
				+ " where tmp.inventory_product_id = s.product_id and s.meter_num = tmp.item_number and s.sample_flag="
				+ sampleFlag
				+ " and s.deleted = 0"
				+ ") and product_id = "
				+ productId
				+ " and sample_flag="
				+ sampleFlag
				+ " and deleted = 0;";

		return (List<Storage>) storageDao.getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery query = session.createSQLQuery(hql);
						List<Object[]> rst = query.list();
						List<Storage> storageList = new ArrayList<Storage>(rst
								.size());
						for (Object[] obj : rst) {
							if (obj != null) {
								Storage st = new Storage();

								if (obj[0] != null)
									st.setId(((BigInteger) obj[0]).longValue());
								if (obj[1] != null)
									st.setDeleted((Short) obj[1]);
								if (obj[2] != null)
									st.setModifier((String) obj[2]);
								if (obj[3] != null)
									st.setModifyTime((Date) obj[3]);
								if (obj[4] != null)
									st.setCreator((String) obj[4]);
								if (obj[5] != null)
									st.setCreateTime((Date) obj[5]);
								if (obj[6] != null)
									st.setName((String) obj[6]);
								if (obj[7] != null)
									st.setSampleFlag((Boolean) obj[7]);
								if (obj[8] != null)
									st.setMeterNum(((BigDecimal) obj[8])
											.doubleValue());
								if (obj[9] != null)
									st.setChargeFlag((Boolean) obj[9]);
								if (obj[10] != null)
									st.setChargedFlowNo((String) obj[10]);
								if (obj[11] != null) {
									Product p = new Product();
									p.setId(((BigInteger) obj[11]).longValue());
									st.setProduct(p);
								}

								storageList.add(st);
							}
						}
						return storageList;
					}
				});
	}

	/**
	 * 查询盘点明细数据中，在库存数据中不存在的相应数据
	 * 
	 * @param productId
	 * @param inventoryId
	 * @return
	 */
	private List<InventoryItem> getInventoryItemNotExistInStorage(
			Long productId, Long inventoryId, Boolean sampleFlag) {
		if (productId == null)
			return null;

		final String hql = "select ii.id, ii.deleted, ii.modifier, ii.modified_time, ii.creator, ii.create_time, ii.inventory_id, ii.meter_num"
				+ " from tim_inventory_inventory_item ii where ii.id not in ("
				+ "select distinct inventory_item_id from "
				+ " (select s.id as storage_id, s.meter_num as storage_meter_num, s.product_id as storage_product_id from tim_inventory_storage s "
				+ "where s.product_id = "
				+ productId
				+ " and s.sample_flag = "
				+ sampleFlag
				+ " and s.deleted = 0) stg inner join "
				+ " (select i.id as inventory_item_id, t.product_id as inventory_product_id, i.meter_num as inventory_item_meter_num "
				+ "from tim_inventory_inventory_item i "
				+ "left outer join tim_inventory_inventory t on i.inventory_id = t.id"
				+ " where t.product_id = "
				+ productId
				+ " and t.id = "
				+ inventoryId
				+ " and t.deleted = 0) inv on inv.inventory_item_meter_num = stg.storage_meter_num"
				+ " ) and ii.inventory_id = " + inventoryId;

		return (List<InventoryItem>) inventoryItemDao.getHibernateTemplate()
				.execute(new HibernateCallback() {

					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery sqlQuery = session.createSQLQuery(hql);
						List<Object[]> rstList = (List<Object[]>) sqlQuery
								.list();
						List<InventoryItem> iiList = new ArrayList<InventoryItem>(
								rstList.size());
						for (Object[] obj : rstList) {
							if (obj != null) {
								InventoryItem ii = new InventoryItem();
								if (obj[0] != null)
									ii.setId(((BigInteger) obj[0]).longValue());
								if (obj[1] != null)
									ii.setDeleted((Short) obj[1]);
								if (obj[2] != null)
									ii.setModifier((String) obj[2]);
								if (obj[3] != null)
									ii.setModifyTime((Date) obj[3]);
								if (obj[4] != null)
									ii.setCreator((String) obj[4]);
								if (obj[5] != null)
									ii.setCreateTime((Date) obj[5]);
								if (obj[6] != null) {
									Inventory inv = new Inventory();
									inv.setId(Long.valueOf(obj[6].toString()));
									ii.setInventory(inv);
								}
								if (obj[7] != null)
									ii.setMeterNum(((BigDecimal)obj[7]).doubleValue());
								iiList.add(ii);
							}
						}
						return iiList;
					}

				});
	}

	/**
	 * 查找都存在的数据
	 * 
	 * @param productId
	 * @param inventoryId
	 * @return
	 */
	private List<Double> getAllExistsMeterNums(Long productId,
			Long inventoryId, Boolean sampleFlag) {
		final String hql = "select distinct storage_meter_num from "
				+ "(select s.id as storage_id, s.meter_num as storage_meter_num, s.product_id as storage_product_id from tim_inventory_storage s where s.deleted=0 and s.sample_flag="
				+ sampleFlag
				+ " and s.product_id = "
				+ productId
				+ ") stg"
				+ " inner join "
				+ " (select i.id as inventory_item_id, t.product_id as inventory_product_id, i.meter_num as inventory_item_meter_num from tim_inventory_inventory_item i left outer join tim_inventory_inventory t on i.inventory_id = t.id "
				+ " where t.product_id = "
				+ productId
				+ " and t.id = "
				+ inventoryId
				+ " and i.deleted = 0) inv on inv.inventory_item_meter_num = stg.storage_meter_num ";
		return (List<Double>) inventoryDao.getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						SQLQuery sqlQuery = session.createSQLQuery(hql);
						List<BigDecimal> rstList = sqlQuery.list();
						List<Double> meterNumList = new ArrayList<Double>(
								rstList.size());
						for (BigDecimal obj : rstList) {
							if (obj != null) {
								if (obj != null)
									meterNumList.add(obj.doubleValue());
							}
						}
						return meterNumList;
					}
				});
	}

	/**
	 * 查询库存和盘点明细中均存在数据中的差异数据
	 * 
	 * @param productId
	 * @param inventoryId
	 * @param meterNum
	 *            map类型，结构为：<"inventory_item",list> 或 <"storage", list>
	 * @return
	 */
	private Map getMarginInExistList(Long productId, Boolean sampleFlag,
			Long inventoryId, Double meterNum) {
		Criteria stgCte = storageDao.createUnDeletedCriteria();
		stgCte.add(Restrictions.eq("product.id", productId));
		stgCte.add(Restrictions.eq("sampleFlag", sampleFlag));
		stgCte.add(Restrictions.eq("meterNum", meterNum));
		stgCte.addOrder(Order.desc("id"));
		List<Storage> existStorageList = stgCte.list();

		Criteria inventoryItemCte = inventoryItemDao.createUnDeletedCriteria();
		inventoryItemCte.add(Restrictions.eq("inventory.id", inventoryId));
		inventoryItemCte.add(Restrictions.eq("meterNum", meterNum));
		inventoryItemCte.createAlias("inventory", "inventory");
		inventoryItemCte.add(Restrictions
				.eq("inventory.sampleFlag", sampleFlag));
		inventoryItemCte.addOrder(Order.desc("id"));
		List<InventoryItem> inventoryItemList = inventoryItemCte.list();

		if (existStorageList.size() == inventoryItemList.size()) {
			// 两边正好对上
			return null;
		}

		Map<String, List> rstMap = new HashMap<String, List>();

		if (existStorageList.size() > inventoryItemList.size()) {
			// 库存数据多于盘点数据，返回库存的差异数据
			rstMap.put("storage", existStorageList.subList(inventoryItemList
					.size() - 1, existStorageList.size() - 1));
		} else {
			// 盘点数据多于库存数据，返回盘点数据
			rstMap.put("inventory_item", inventoryItemList.subList(
					existStorageList.size() - 1, inventoryItemList.size() - 1));
		}
		return rstMap;
	}

	/**
	 * 更新录入的盘点数据，处理时会将所有先前的数据全部物理删除，然后重新录入
	 * 
	 * @return
	 */
	public boolean updateInventory(List<InventoryItem> iList, Long inventoryId) {
		boolean rst = false;
		if (iList != null && iList.size() > 0 && inventoryId != null) {
			Inventory inv = inventoryDao.get(inventoryId);
			if (inv != null) {
				inventoryItemDao.deleteItemByInventoryId(inventoryId); // 物理删除原始记录
				double totalMeterNum = 0; // 总米数
				double totalPiNum = 0;// 总匹数
				for (InventoryItem item : iList) {
					if (item != null && item.getMeterNum() != null
							&& item.getMeterNum().doubleValue() != 0) {
						item.setId(null);
						item.setInventory(inv);
						inventoryItemDao.save(item);// 保存

						totalMeterNum += item.getMeterNum().doubleValue();
						totalPiNum++;
					} else {
						continue;
					}
				}

				inv.setTotalMeterNum(totalMeterNum);
				inv.setTotalPiNum(totalPiNum);
				rst = true;
			}

		}
		return rst;
	}

	/**
	 * 
	 * @param inventoryId
	 * @return
	 */
	public List<InventoryMarginItem> getMarginListData(Long inventoryId) {
		List<InventoryMarginItem> list = null;
		if (inventoryId != null) {
			Criteria cte = inventoryMarginItemDao.createUnDeletedCriteria();
			cte.add(Restrictions.eq("inventory.id", inventoryId));
			list = (List<InventoryMarginItem>) cte.list();
		}
		return list;
	}

	public boolean deleteInv(Long id) {
		boolean rst = false;
		if (id != null) {
			Inventory inv = inventoryDao.get(id);
			if (inv != null) {
				String marginHQL = "delete from com.easidea.tim.entity.inventory.InventoryMarginItem imi where imi.inventory.id = :invId";
				Query marginDeleteQuery = inventoryMarginItemDao
						.createQuery(marginHQL);
				marginDeleteQuery.setParameter("invId", id);

				String itemHQL = "delete from com.easidea.tim.entity.inventory.InventoryItem ii where ii.inventory.id = :invId";
				Query itemDeleteQuery = inventoryItemDao.createQuery(itemHQL);
				itemDeleteQuery.setParameter("invId", id);

				String invHQL = "delete from com.easidea.tim.entity.inventory.Inventory i where i.id = :invId";
				Query invQuery = inventoryDao.createQuery(invHQL);
				invQuery.setParameter("invId", id);

				int margenDeleteCounts = marginDeleteQuery.executeUpdate();
				int itemDeleteCounts = itemDeleteQuery.executeUpdate();
				invQuery.executeUpdate();

				log.debug("Inventory with id : " + id
						+ " has been deleted and deleted " + itemDeleteCounts
						+ " items and " + margenDeleteCounts + " margins");
				rst = true;
			}
		}
		return rst;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.springside.core.service.EntityService#getEntityDao()
	 */
	@Override
	public InventoryDao getEntityDao() {
		return inventoryDao;
	}

	/**
	 * @return the inventoryDao
	 */
	public InventoryDao getInventoryDao() {
		return inventoryDao;
	}

	/**
	 * @param inventoryDao
	 *            the inventoryDao to set
	 */
	public void setInventoryDao(InventoryDao inventoryDao) {
		this.inventoryDao = inventoryDao;
	}

	/**
	 * @return the inventoryItemDao
	 */
	public InventoryItemDao getInventoryItemDao() {
		return inventoryItemDao;
	}

	/**
	 * @param inventoryItemDao
	 *            the inventoryItemDao to set
	 */
	public void setInventoryItemDao(InventoryItemDao inventoryItemDao) {
		this.inventoryItemDao = inventoryItemDao;
	}

	/**
	 * @return the inventoryMarginItemDao
	 */
	public InventoryMarginItemDao getInventoryMarginItemDao() {
		return inventoryMarginItemDao;
	}

	/**
	 * @param inventoryMarginItemDao
	 *            the inventoryMarginItemDao to set
	 */
	public void setInventoryMarginItemDao(
			InventoryMarginItemDao inventoryMarginItemDao) {
		this.inventoryMarginItemDao = inventoryMarginItemDao;
	}

	/**
	 * @return the productDao
	 */
	public ProductDao getProductDao() {
		return productDao;
	}

	/**
	 * @param productDao
	 *            the productDao to set
	 */
	public void setProductDao(ProductDao productDao) {
		this.productDao = productDao;
	}

	/**
	 * @return the storageDao
	 */
	public StorageDao getStorageDao() {
		return storageDao;
	}

	/**
	 * @param storageDao
	 *            the storageDao to set
	 */
	public void setStorageDao(StorageDao storageDao) {
		this.storageDao = storageDao;
	}

	/**
	 * @return the checkInOutDao
	 */
	public CheckInOutDao getCheckInOutDao() {
		return checkInOutDao;
	}

	/**
	 * @param checkInOutDao
	 *            the checkInOutDao to set
	 */
	public void setCheckInOutDao(CheckInOutDao checkInOutDao) {
		this.checkInOutDao = checkInOutDao;
	}

	/**
	 * @return the checkInOutItemDao
	 */
	public CheckInOutItemDao getCheckInOutItemDao() {
		return checkInOutItemDao;
	}

	/**
	 * @param checkInOutItemDao
	 *            the checkInOutItemDao to set
	 */
	public void setCheckInOutItemDao(CheckInOutItemDao checkInOutItemDao) {
		this.checkInOutItemDao = checkInOutItemDao;
	}

	/**
	 * @return the flowNoDao
	 */
	public FlowNoDao getFlowNoDao() {
		return flowNoDao;
	}

	/**
	 * @param flowNoDao
	 *            the flowNoDao to set
	 */
	public void setFlowNoDao(FlowNoDao flowNoDao) {
		this.flowNoDao = flowNoDao;
	}

}
